package com.tianji.promotion.service.impl;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.common.domain.dto.PageDTO;
import com.tianji.common.utils.BeanUtils;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.promotion.domain.po.Coupon;
import com.tianji.promotion.domain.po.ExchangeCode;
import com.tianji.promotion.domain.query.CodeQuery;
import com.tianji.promotion.domain.vo.ExchangeCodeVo;
import com.tianji.promotion.enums.ExchangeCodeStatus;
import com.tianji.promotion.mapper.ExchangeCodeMapper;
import com.tianji.promotion.service.IExchangeCodeService;
import com.tianji.promotion.utils.CodeUtil;
import org.springframework.data.redis.core.BoundValueOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

import static com.tianji.promotion.contants.PromotionContants.COUPON_CODE_MAP_KEY;
import static com.tianji.promotion.contants.PromotionContants.COUPON_CODE_SERIAL_KEY;

/**
 * <p>
 * 兑换码 服务实现类
 * </p>
 *
 * @author xzh
 * @since 2024-03-20
 */
@Service

public class ExchangeCodeServiceImpl extends ServiceImpl<ExchangeCodeMapper, ExchangeCode> implements IExchangeCodeService {
    BoundValueOperations<String, String> ops;
    private final StringRedisTemplate redisTemplate;

    public ExchangeCodeServiceImpl(StringRedisTemplate redisTemplate){
        this.redisTemplate=redisTemplate;
        this.ops = redisTemplate.boundValueOps(COUPON_CODE_SERIAL_KEY);
    }

    /**
     * 新增兑换码
     * @param coupon
     */
    @Override
    @Async("generateExchangeCodeExecutor")
    @Transactional
    public void saveExchangeCode(Coupon coupon) {
        //1.获得递增id 根据兑换码发行数量
        //发行数量
        Integer totalNum = coupon.getTotalNum();
        Long result = ops.increment(totalNum);
        if (result==null){
            return;
        }
        int maxSerialNum = result.intValue();
        //2.循环生成一定数量的兑换码
        Long userId = UserContext.getUser();
        List<ExchangeCode> list=new ArrayList<>(maxSerialNum);
        for (int i=maxSerialNum-totalNum+1;i<=maxSerialNum;i++){
            String code = CodeUtil.generateCode(i, coupon.getId());
            ExchangeCode e=new ExchangeCode();
            e.setCode(code);
            e.setStatus(ExchangeCodeStatus.UNUSED);
            e.setCreateTime(LocalDateTime.now());
            e.setExpiredTime(coupon.getIssueEndTime());
            e.setExchangeTargetId(coupon.getId());
            e.setId(i);
            e.setUserId(userId);
            list.add(e);
        }
        //3.批量导入数据库
        saveBatch(list);
        /*//4.在redis中保存递增数字已经用到哪里了,防止code重复
        redisTemplate.opsForZSet().add(COUPON_CODE_SERIAL_KEY,coupon.getId().toString(),maxSerialNum);*/
    }

    /**
     * 兑换码分页查询
     * @param query
     * @return
     */
    @Override
    public PageDTO<ExchangeCodeVo> queryExchangeCodePage(CodeQuery query) {
        //获得分页数据
        Page<ExchangeCode> page = lambdaQuery()
                .eq(ExchangeCode::getExchangeTargetId, query.getCouponId())
                .eq(ExchangeCode::getStatus, query.getStatus())
                .page(query.toMpPageDefaultSortByCreateTimeDesc());
        //获得分页资源
        List<ExchangeCode> records = page.getRecords();
        if (CollUtils.isEmpty(records)){
            return PageDTO.empty(0L,0L);
        }
        //拷贝
        List<ExchangeCodeVo> list = BeanUtils.copyList(records, ExchangeCodeVo.class);
        //返回
        return PageDTO.of(page,list);
    }

    /**
     * 在redis中修改并  获取code以前状态
     * @param serialNum
     * @param b
     * @return
     */
    @Override
    public boolean updateExchangeMake(long serialNum, boolean b) {
        Boolean exchanged = redisTemplate.opsForValue().setBit(COUPON_CODE_MAP_KEY, serialNum, b);
        return exchanged!=null &&exchanged;
    }

    /**
     * 修改兑换码状态为已使用 添加使用人
     * @param userId
     * @param status
     * @param serialNum
     */
    @Override
    public void happyLockUpdateCodeById(Long userId, ExchangeCodeStatus status,
                                        ExchangeCodeStatus oldStatus, long serialNum) {
        ExchangeCodeMapper.happyLockUpdateCodeById(userId, status,oldStatus, serialNum);
    }
}
